﻿#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // Each user gets 1000 free API calls for each end point every 30 days
    // with a rate limited of 1 call per second.
    // snowboy的厂商KITT.AI 2017年已被百度收购
    detector = new SnowboyDetect("/home/student/snowboy-1.3.0/resources/common.res",
                                 "/home/student/snowboy-1.3.0/resources/models/snowboy.umdl");
    detector->SetSensitivity("0.5");
    detector->SetAudioGain(1);

    QAudioFormat format;
    format.setSampleRate(detector->SampleRate());
    format.setChannelCount(detector->NumChannels());
    format.setSampleSize(detector->BitsPerSample());
    format.setSampleType(QAudioFormat::SignedInt);
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setCodec("audio/pcm");
    recorder = new QAudioInput(format, this);

    data = new QBuffer(this);
    data->open(QIODevice::ReadWrite);

    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Widget::detect_hotword);

    timer->start(1000);
}

// 每秒执行一次检测函数，当这一秒钟内的声音数据中包含关键词时会检测成功，漏检的概率比较大，
// 并且关键词的长度不能超过1秒钟。比较好的做法是使用FIFO队列或环形缓冲区记录最近5秒的声音数据，
// 每100毫秒进行一次入队和出队操作，然后对缓冲区中的声音数据进行检测，实时性好而且漏检概率非常小，
// 可以按照这个思路进行优化。
void Widget::detect_hotword()
{
    //如果不是第一次调用本函数则进行检测
    if (recorder->state() == QAudio::ActiveState)
    {
        recorder->stop();
        //RunDetection函数返回值的含义
        //    -2    没有声音
        //    -1    出错
        //     0    有声音但不是关键词
        //    >0    检测到关键词
        int ret = detector->RunDetection(data->data().toStdString());
        if (ret > 0)
        {
            ui->textBrowser->append("Hotword detected");
        }
        data->reset();//清空已检测的声音数据，重新录音
    }
    recorder->start(data);
}

Widget::~Widget()
{
    recorder->stop();
    delete ui;
    delete detector;
}

